package com.gitee.apanlh.util.base;

import com.gitee.apanlh.util.valid.ValidParam;

import java.util.function.BiPredicate;

/**	
 * 	选择工具类
 * 	<br>包含或、与、范围值选择
 * 	<br>可以用于简化代码使用
 * 	<br>例如：多个if-elseif-else、多个范围校验等等场景使用
 * 	
 * 	@author Pan
 */
public class Choose {
	
	/**
	 * 	默认构造函数
	 * 
	 * 	@author Pan
	 */
	private Choose() {
		// 不允许外部构造
		super();
	}
	
	/**	
	 * 	与条件
	 * 	<br>如果都验证结果全部返回true则返回value值
	 * 	
	 * 	@author Pan
	 * 	@param 	<R>			返回类型
	 * 	@param 	value		实例对象
	 * 	@param 	chooseAnd	选择条件
	 * 	@return	R
	 */
	public static <R> R and(R value, boolean... chooseAnd) {
		if (ValidParam.isEmpty(chooseAnd)) {
			return null;
		}
		
		for (int i = 0; i < chooseAnd.length; i++) {
			if (!chooseAnd[i]) {
				return null;
			}
		}
		return value;
	}

	/**
	 * 	开区间选择 (start, end)
	 * 	
	 * 	@author Pan
	 * 	@param 	start 	起始值
	 * 	@param 	end   	结束值
	 * 	@param 	value 	要判断的值
	 * 	@param 	<T>   	条件值的类型
	 * 	@return boolean	true表示在开区间内，false表示在区间外
	 */
	public static <T extends Comparable<T>> boolean open(T start, T end, T value) {
		BiPredicate<T, T> predicate = (v1, v2) -> v1.compareTo(start) > 0 && v1.compareTo(end) < 0;
		return predicate.test(value, value);
	}

	/**
	 * 	创建闭区间选择 [start, end]
	 * 
	 * 	@author Pan
	 * 	@param 	start 	起始值
	 * 	@param 	end   	结束值
	 * 	@param 	value 	要判断的值
	 * 	@param 	<T>   	条件值的类型
	 * 	@return	boolean	true表示在闭区间内，false表示在区间外
	 */
	public static <T extends Comparable<T>> boolean closed(T start, T end, T value) {
		BiPredicate<T, T> predicate = (v1, v2) -> v1.compareTo(start) >= 0 && v2.compareTo(end) <= 0;
		return predicate.test(value, value);
	}

	/**
	 * 	创建左闭右开(半开半闭/半开区间)区间选择 [start, end)
	 * 	
	 * 	@author Pan
	 * 	@param 	start 	起始值
	 * 	@param 	end   	结束值
	 * 	@param 	value 	要判断的值
	 * 	@param 	<T>   	条件值的类型
	 * 	@return boolean	true表示在左闭右开区间内，false表示在区间外
	 */
	public static <T extends Comparable<T>> boolean closedOpen(T start, T end, T value) {
		BiPredicate<T, T> predicate = (v1, v2) -> v1.compareTo(start) >= 0 && v2.compareTo(end) < 0;
		return predicate.test(value, value);
	}

	/**
	 * 	创建左开右闭区间选择 (start, end]
	 * 	
	 * 	@author Pan
	 * 	@param 	start 	起始值
	 * 	@param 	end   	结束值
	 * 	@param 	value 	要判断的值
	 * 	@param 	<T>   	条件值的类型
	 * 	@return boolean	true表示在左开右闭区间内，false表示在区间外
	 */
	public static <T extends Comparable<T>> boolean openClosed(T start, T end, T value) {
		BiPredicate<T, T> predicate = (v1, v2) -> v1.compareTo(start) > 0 && v2.compareTo(end) <= 0;
		return predicate.test(value, value);
	}

	/**
	 * 	创建左开区间选择 (-∞, end)
	 * 	<br>小于
	 * 
	 * 	@author Pan
	 * 	@param 	end   	结束值
	 * 	@param 	value 	要判断的值
	 * 	@param 	<T>   	条件值的类型
	 * 	@return boolean	true表示在左开区间内，false表示在区间外
	 */
	public static <T extends Comparable<T>> boolean leftOpen(T end, T value) {
		BiPredicate<T, T> predicate = (v1, v2) -> v2.compareTo(end) < 0;
		return predicate.test(value, value);
	}

	/**
	 * 	创建右开区间选择 (start, +∞)
	 * 	<br>大于
	 * 
	 * 	@author Pan
	 * 	@param 	start 	起始值
	 * 	@param 	value 	要判断的值
	 * 	@param 	<T>   	条件值的类型
	 * 	@return	boolean	true表示在右开区间内，false表示在区间外
	 */
	public static <T extends Comparable<T>> boolean rightOpen(T start, T value) {
		BiPredicate<T, T> predicate = (v1, v2) -> v1.compareTo(start) > 0;
		return predicate.test(value, value);
	}

	/**
	 * 	创建左闭区间选择 (-∞, end]
	 * 	<br>小于等于
	 * 
	 * 	@author Pan
	 * 	@param 	end   	结束值
	 * 	@param 	value 	要判断的值
	 * 	@param 	<T>   	条件值的类型
	 * 	@return boolean true表示在左闭区间内，false表示在区间外
	 */
	public static <T extends Comparable<T>> boolean leftClose(T end, T value) {
		BiPredicate<T, T> predicate = (v1, v2) -> v2.compareTo(end) <= 0;
		return predicate.test(value, value);
	}
	
	/**
	 * 	创建右闭区间选择 [start, +∞)
	 * 	<br>大于等于
	 * 
	 * 	@author Pan
	 * 	@param 	start 	起始值
	 * 	@param 	value 	要判断的值
	 * 	@param 	<T>   	条件值的类型
	 * 	@return boolean	true表示在右闭区间内，false表示在区间外
	 */
	public static <T extends Comparable<T>> boolean rightClose(T start, T value) {
		BiPredicate<T, T> predicate = (v1, v2) -> v1.compareTo(start) >= 0;
		return predicate.test(value, value);
	}
}
